// app配置
import AppConf from "@/config";
import { getSocket, getUuid } from "./socket";
import Vue from "vue";

import {
  UPDATE_SOCKET,
  CLEAR_SOCKET,
  CLOSE_SOCKET_ALL
} from "./mutation-types";

const state = {
  store_socket: {}
};

const getters = {};

const actions = {
  /* connection默认，可通过传参修改
    data, 发送给服务端的数据{type: type,message: message}
    methods, 挂载在socket上面的方法，以服务端响应type为准
    repeat, 是否需要重复新开请求，有部分连接是组件内的，找不到相应
  */
  sendSocket({ dispatch, state, rootState }, param) {
    return new Promise(resolve => {
      if (!param.connection) {
        param.isDefaultConnection = true;
      }
      const {
        connection = `${AppConf.$config.domain.socketUrl}${
          rootState.user.currentTokenUser.user.userId
        }?token=${window.sessionStorage.getItem("token")}`,
        data,
        methods,
        repeat = false,
        appendUuid = true
      } = param;
      // 新建连接,添加uuid(流程里进入页面会建立连接等待，无法判断接收方)
      if (repeat) {
        dispatch("openNewSocket", {
          ...param,
          connection: appendUuid
            ? `${connection}${
                connection.includes("?") ? "&connectionId=" : "?connectionId="
              }${getUuid()}`
            : connection,
          appendUuid: false
        }).then(newSocket => {
          dispatch("sendData", { socket: newSocket, data, methods });
          resolve(newSocket);
        });
        return;
      }
      // 如果连接存在，就用当前连接
      if (state.store_socket[connection]) {
        const socket = state.store_socket[connection].socket;
        const { readyState } = socket;
        // 发送数据时如果连接已关闭，就新开一个连接
        if (readyState > 1) {
          dispatch("openNewSocket", {
            ...param,
            connection
          }).then(newSocket => {
            dispatch("sendData", { socket: newSocket, data, methods });
            resolve(newSocket);
          });
          return;
        }
        dispatch("sendData", { socket, data, methods });
        resolve(socket);
      } else {
        // 连接不存在，就新建连接
        dispatch("openNewSocket", {
          ...param,
          connection
        }).then(newSocket => {
          dispatch("sendData", { socket: newSocket, data, methods });
          resolve(newSocket);
        });
      }
    });
  },
  openNewSocket({ commit, dispatch }, param) {
    return new Promise((resolve, reject) => {
      const { connection = "", appendUuid = true, isDefaultConnection } = param;
      getSocket({ connection, appendUuid })
        .then(socket => {
          // 添加断线重连监听,重连后监听一次进行新建连接
          // 只会断线重连默认连接，重连其它连接会出问题
          function onlineOpen() {
            dispatch("openNewSocket", param);
          }
          // 新建默认连接时需要先移除之前的监听（去除断线重连，用户集中在一个网段，而且可开多窗口建立连接，并发严重）
          if (isDefaultConnection) {
            // Vue.prototype.$EventBus.$off("socket_online");
            // Vue.prototype.$EventBus.$on("socket_online", onlineOpen);
          }
          // 记录连接
          commit(UPDATE_SOCKET, {
            socket_key: connection,
            socket
          });
          resolve(socket);
        })
        .catch(() => {
          reject();
        });
      // 清除已经关闭的socket连接
      commit(CLEAR_SOCKET, {});
    });
  },
  async sendData({ commit }, param) {
    const { socket, data, methods } = param;
    if (!socket.methods) {
      socket.methods = {};
    }
    // 发送数据并添加回调
    for (let item in methods) {
      socket.methods[item] = methods[item];
    }
    if (!data) {
      return;
    }
    socket.send(JSON.stringify(data));
  }
};
const mutations = {
  [UPDATE_SOCKET](state, payload) {
    const { socket_key, socket } = payload;
    // 同一个地址只建立一条链接 如果重复需要先关掉之前的
    if (state.store_socket[socket_key]) {
      try {
        // 把之前连接的回调备份
        if (!socket.methods) {
          socket.methods = state.store_socket[socket_key].socket.methods || {};
        }
        state.store_socket[socket_key].socket.close();
      } catch {
        console.log("之前的socket连接关闭失败");
      }
    }

    state.store_socket[socket_key] = {
      socket
    };
  },
  [CLEAR_SOCKET](state, payload) {
    // 清除已经关闭的socket
    for (let item in state.store_socket) {
      if (state.store_socket[item].readyState > 1) {
        delete state.store_socket[item];
      }
    }
  },
  [CLOSE_SOCKET_ALL](state, payload) {
    // 关闭所有socket连接（只在卸载页面时调用，其它时刻禁止调用）
    for (let item in state.store_socket) {
      if (state.store_socket[item].socket.readyState === 1) {
        state.store_socket[item].socket.close();
      }
    }
  }
};

export default {
  state,
  getters,
  actions,
  mutations
};
